Skip to content

test: add failing test reproducing #113 (GIL held during blocking I/O) - #114

Open
monperrus wants to merge 1 commit into
tursodatabase:mainfrom
monperrus:test/repro-issue-113
Open

test: add failing test reproducing #113 (GIL held during blocking I/O)#114
monperrus wants to merge 1 commit into
tursodatabase:mainfrom
monperrus:test/repro-issue-113

Conversation

@monperrus

Copy link
Copy Markdown

Adds a regression test for #113 that reproduces the root cause without needing a remote Hrana server.

It blocks one local connection against another via sqlite's busy handler (a real blocking call inside the extension, same code path as a stuck Hrana call) and asserts a background Python thread keeps making progress while the call is blocked. It currently fails on main:

AssertionError: background thread only ticked 2 times while cursor.execute() was blocked for ~1.5s -- GIL was likely held during the blocking call

This confirms the mechanism behind the issue: cursor.execute() (and commit/rollback/fetch*/executemany/executescript) call into blocking Rust code without releasing the GIL. When the underlying call hangs, the whole interpreter freezes, including any other thread -- which is also why a concurrent.futures-based timeout wrapped around the call from another thread never actually fires (the watcher thread's OS-level timed wait elapses, but it then blocks trying to reacquire the GIL from the thread stuck inside the extension call).

No behavior/source changes here, test only.

…ing I/O)

cursor.execute() (and commit/rollback/fetch*/executemany/
executescript) call into blocking Rust code without releasing the
GIL. When the underlying call blocks -- e.g. waiting on sqlite's busy
handler for a lock, or (per the linked issue) on a stuck Hrana stream
-- the whole interpreter freezes, including any other Python thread.
This is why a concurrent.futures-based timeout wrapped around the
call from another thread never fires: the watcher thread's timed wait
elapses at the OS level, but it then blocks trying to reacquire the
GIL from the thread stuck inside the extension call, since that
thread never released it.

This test blocks one connection against another via sqlite's busy
handler (no remote server required) and asserts a background thread
keeps ticking during the wait. It currently fails:

    AssertionError: background thread only ticked 2 times while
    cursor.execute() was blocked for ~1.5s -- GIL was likely held
    during the blocking call

Ref: tursodatabase#113
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant